package core.manager;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.log4j.Logger;
import core.comunication.MessageServer;
import core.descriptors.TaskDescriptor;
import core.interfaces.TQueue;
import core.util.COREServiceRegistry;
import core.worker.Address;

/**
 * Classe che gestisce la coda dei Task. Contiente una BlockingQueue di TaskDescriptor
 * Implementa l'interfaccia TQueue.
 * @author Vincenzo Merlo, Scuderi Giovanni Luca, Paolo Giuffrida
 *
 */
public class TQueueManager implements TQueue {

    private final Logger logger = COREServiceRegistry.getLogger(TQueueManager.class.toString());
    private BlockingQueue<TaskDescriptor> tQueue;
    private Address addr = null;

    /**
     * Costruttore
     */
    public TQueueManager(Address addr) {
        //Istanzio la coda
        tQueue = new LinkedBlockingQueue<TaskDescriptor>();

        this.addr = addr;
        System.out.println(addr);
        
        //lancio il server udp che effetta l'enqueue
        udpServer();
    }

    /**
     * Ritorna il TaskDescriptor presente nella testa della coda
     * @return TaskDescriptor in testa
     */
    @Override
    public synchronized TaskDescriptor dequeue() {
        logger.info("dequeue");
        try {
            final TaskDescriptor tf;
            //final BlockingQueue<TaskDescriptor> wfq = tQueue;
            //synchronized (wfq) {
            tf = gettQueue().take(); //TODO: ottimizzare meccanismo di sincronizzazione
            //}

            return tf;
        } catch (InterruptedException e) {
            logger.error("Error dequeue" + e.getStackTrace());
        }

        return null;
    }

    /**
     * Inserisce un Task in coda
     * @param TaskDescriptor da inserire
     * @return int > 0, posizione di inserimento, -1 errore
     */
    @Override
    public int enqueue(TaskDescriptor td) {
        final TQueueManager queue = this;
        logger.debug("***************************************************************enqueue");
        synchronized (queue) {
            if (gettQueue().add(td)) {
                queue.notify();
                logger.debug("enqueue");
                return gettQueue().size() - 1;
            } else {
                logger.error(" Error enqueue , limited reached");
            }
            return -1; //TODO ERROR
        }

    }

    /**
     * Istanzia MessageServer
     * @see MessagesServer
     */
    protected void udpServer() {
        MessageServer.getInstance().setAddr(addr);
        MessageServer.getInstance().setTQ(this);
        MessageServer.getInstance().start();
        
    }

    /**
     *
     * @return string
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(TQueueManager.class.getSimpleName());
        for (TaskDescriptor td : this.gettQueue()) {
            sb.append("\n\t").append(td);
        }

        return sb.toString();
    }

    /**
     * Ritorna la coda di TaskDescriptor
     * @return la coda, BlockingQueue, di TaskDescriptor
     */
    public BlockingQueue<TaskDescriptor> gettQueue() {
        return tQueue;
    }

    /**
     * Setta la coda, BlockingQueue, di Task
     * @param BlockingQueue, coda di Task, da settare
     */
    public void settQueue(BlockingQueue<TaskDescriptor> tQueue) {
        this.tQueue = tQueue;
    }

    /**
     * Setta l'Address
     * @param Address da settare
     */
    public void setAddr(Address addr) {
            this.addr = addr;
    }

    /**
     * Ritorna l'Address
     * @return Address
     */
    public Address getAddr() {
            return addr;
    }
}
